#ifndef DRAWINGAREA_H
#define DRAWINGAREA_H

#include <QImage>
#include <QGraphicsView>
#include <QGraphicsPixmapItem>
#include <QPixmap>
#include <QRgb>
#include <QPrinter>
#include <QMouseEvent>
#include <QFileDialog>
#include <QStyleOptionGraphicsItem>
#include <QBrush>
#include <QColor>
#include <QPicture>
#include <QGridLayout>
#include <QMouseEvent>
#include <iostream>
#include <QSemaphore>
#include <QWheelEvent>
#include <QObject>
#include <list>

#include "pimage.h"
#include "Filter/filter.h"
#include "Layer/layer.h"
#include "GraphicsArea/tooleffect.h"
#include "GraphicsArea/selectionrect.h"
#include "GraphicsArea/cropping.h"
#include "GraphicsArea/takecolor.h"
#include "GraphicsArea/borderlayer.h"
#include "Fusion/fusionlayers.h"
#include "GraphicsArea/mover.h"
#include "GraphicsArea/background.h"
#include "GraphicsArea/moverselection.h"
#include "GraphicsArea/pencil.h"

class PImage;

enum e_tool{ // when user choose a tool, he pass on one of those mode.
    Cropped,
    Take_Color,
    Selection_Rect,
    Clever_Selection,
    Moved_Tool,
    MovedSelection_Tool,
    Pencil_Tool
};

// class use to define an area where the user could visualise images, and where he could work on it
class DrawingArea : public QGraphicsView
{
    Q_OBJECT
public:
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Constructors
    DrawingArea(PImage* pimg);
    DrawingArea(PImage* pimg, int width, int height);
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Load and save
    void load(const QString fileName);
    void save(const QString fileName);
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Render and Resize
    QImage render();
    void resize(int width, int height);
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Filter
    void applyFilter(Filter* filter);
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Tools
    void setTool(e_tool newSelectTool, QDockWidget* dockInfoTool);
    QCursor cursorTool(e_tool tool);
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Function Select ALL
    void selectAll(QDockWidget* dockInfoTool);
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Rotation
    void rotate(qreal angle);
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Mirors
    void MiroirVertical();
    void MiroirHorizontal();
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Copy & Paste
    Layer* copy();
    void paste(Layer* layer);
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Operation on the layers
    void addLayerAfterCurrentLayer();
    void addLayerBeforeCurrentLayer();
    void addLayerAfterCurrentLayer(Layer* layer);
    void addLayerBeforeCurrentLayer(Layer* layer);
    void removeCurrentLayer();
    void removeLayer(Layer* layerToRemove);
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Operation on the layers
    void selectTheLowerLayer();
    void selectTheUpperlayer();
    void selectTheLowestLayer();
    void selectTheUppestLayer();
    void takeDownTheLayer();
    void takeUpTheLayer();
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Fusion
    void fusionVisibleLayers(e_fusion typeFusion);
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Set
    void setWidth(int width);
    void setHeight(int height);
    void setCurrentLayer(Layer* layer);
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Get
    int getWidth();
    int getHeight();
    int getMargeSceneX();
    int getMargeSceneY();
    std::list <Layer*> getListLayers();
    int getLayersCount();
    Layer* getCurrentLayer();
    std::list <Layer*> getLayers();
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Zoom
    void scale( qreal sx, qreal sy );
    qreal getScale();
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Variables tools
    e_tool currentTool;
    Selection* selection;
    Cropping* cropping;
    Mover* mover;
    MoverSelection* moverSelection;
    BorderLayer* borderLayer;
    Background* background;
    Pencil* pencil;
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Variables tools Selection
    int XBeginSelection;
    int XEndSelection;
    int YBeginSelection;
    int YEndSelection;
private:
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Variables drawing
    int width, height;
    int margeSceneX;
    int margeSceneY;
    std::list <Layer*> listLayers;
    Layer* currentLayer;
    qreal scaleXY;
    bool controlPressed;
    QSemaphore* semaphore;
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Variables pointers
    PImage* pimage;
    TakeColor* takeColor;
public slots:
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Update
    void update();
    void updateProprietyLayer();
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Key event
    void keyPressEvent(QKeyEvent* key);
    void keyReleaseEvent(QKeyEvent* key);
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Mouse event
    void wheelEvent (QWheelEvent* e);
    void mousePressEvent(QMouseEvent* event);
    void mouseMoveEvent (QMouseEvent* event);
    void mouseReleaseEvent (QMouseEvent * event);
};
#endif // DRAWINGAREA_H
